/*
 * pserver.c
 *
 *  Created on: 2011-6-20
 *      Author: vyouzhi
 */

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#include "socketbase.h"
#include "conf_lib.h"


int Epoll_init(int sockfd){
	int s;
	
	efd = epoll_create(MAXEPOLLS);
	
	if (efd == -1){
      		printf("epoll_create");
		return (-1);
    	}

	event.data.fd = sockfd;
	event.events = EPOLLIN | EPOLLET;
  	s = epoll_ctl (efd, EPOLL_CTL_ADD, sockfd, &event);
	if (s == -1){
	      printf("epoll_ctl");
      	      return (-1);
    	}

  	/* Buffer where events are returned 
  	events = calloc (MAXEVENTS, sizeof event);*/
	
	return (0);
}

int Epoll_wait(void){
	int n;
	n = epoll_wait(efd, events, MAXEVENTS, -1);
	return n;	
}

int Epoll_EvteqSfd(int i, int sockfd){
	if (events[i].data.fd == sockfd){
		return (0);
	}else{
		return (-1);
	}
}

int Epoll_EvteqIn(int i){
	if (events[i].events & EPOLLIN){
		return (0);
	}else return (-1);

}

int Epoll_EvteqOut(int i){
	if (events[i].events & EPOLLOUT)return (0);
	else return (-1);
}

int Epoll_getEvtfd(int i){
	int connfd;
	connfd = events[i].data.fd;
        return connfd;
}

int Epoll_Error(int i){

	if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) ){
		fprintf (stderr, "epoll error\n");
		close (events[i].data.fd);
		return (-1);
	}else{ return (0);}
	
}

int Epoll_accept_init(int cfd){
	int s;
	event.data.fd = cfd;
        event.events = EPOLLIN | EPOLLET;
        s = epoll_ctl(efd, EPOLL_CTL_ADD, cfd, &event);
        if (-1 == s){
        	printf("epoll_ctl EPOLLIN | EPOLLET\n");
                return (-1);
        }
	return (0);	
}

int Epoll_recv_init(int cfd, int totallen, int recvCount){
	int s;
	
	event.data.fd = cfd;
	if(totallen > recvCount){
		event.events=EPOLLIN|EPOLLET;
		/*c->recvStatus = 1;*/
	}else{
		event.events=EPOLLOUT|EPOLLET;
	}               

	s = epoll_ctl(efd,EPOLL_CTL_MOD,cfd,&event);

	if (-1 == s){
		printf("epoll_ctl error on EPOLLOUT|EPOLLET\n");
		return -1;
	}
	return 0;
}

int Epoll_close(int i, int cfd){
	int s;

	event.data.fd = cfd;
               
	/*ev.events=EPOLLIN|EPOLLET;*/
			
	/*if (c->recvStatus == 1){*/
	s = epoll_ctl(efd, EPOLL_CTL_DEL, cfd, &event);
	if(-1 == s){
		printf("epoll_ctl error EPOLL_CTL_DEL\n");
		/*return (-1);*/
	}
	close(cfd);
	events[i].data.fd = -1;
	/*}*/
	return (0);
}

int SetNonBlocking(int s){
    int opts;
    opts=fcntl(s, F_GETFL);
    if(opts == -1)
    {
        perror("fcntl(sock,GETFL)");
        exit(-1);
    }
    opts |= O_NONBLOCK;
    if(fcntl(s, F_SETFL, opts) == -1)
    {
        perror("fcntl(sock,SETFL,opts)");
        exit(1);
    }
	return 0;
}

int Server_init(){

	int sockfd;
	struct sockaddr_in   server_addr;
	int port, max_link;
	char *host;
	
	host = conf_get("server_ip");
	port = atoi(conf_get("server_port"));
	max_link = atoi(conf_get("max_link"));

	bzero(&server_addr, sizeof(server_addr));
	inet_pton(AF_INET, host, &(server_addr.sin_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	
	if (-1 == sockfd) {return(-1);}

	if (-1 == Set_SockOpt(sockfd)) {
		close(sockfd);
		return (-1);
	}

	if (-1 == bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
		close(sockfd);
		return(-1);
	}
	if (-1 == SetNonBlocking(sockfd)){
		close(sockfd);
		return (-1);
	}
	if (-1 == listen(sockfd, max_link)) {
		close(sockfd);
		return(-1);
	}
	
	return(sockfd);
}

int Set_SockOpt(int sockfd){
	int reuse=1;	
	int sock_buf_size = 65000;
	struct linger opt;

	if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse,
		sizeof(int))) {
		printf("Couldn't setsockopt(SO_REUSEADDR)\n");
		return (-1);
	}
	
	if (-1 == setsockopt( sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size,
		sizeof(sock_buf_size) )) {
		printf("Couldn't setsockopt(SO_SNDBUF)\n");
		return (-1);
	}

	if (-1 == setsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&sock_buf_size,
		sizeof(sock_buf_size) )) {
		printf("Couldn't setsockopt(SO_RCVBUF)\n");
		return (-1);
	}
	
	opt.l_onoff = 1;
	opt.l_linger = 60;

	if (-1 == setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &opt,
		sizeof(struct linger))){
		printf("Coundn't setsockopt(SO_LINGER)\n");
		return (-1);
	}

	return 0;
}

int Socket_accept(int sockfd){
	struct sockaddr_in    cli_addr;
	socklen_t addrlen;
	int cli_fd;
	addrlen = sizeof(cli_addr);
	bzero(&cli_addr, addrlen);
	cli_fd = accept(sockfd, (struct sockaddr *)&cli_addr, &addrlen);
	if(-1 == cli_fd){
		return (-1);
	}
	SetNonBlocking(cli_fd);
	
	return cli_fd;
}

int Socket_recv(int i, int sockfd, char **data){
	char buff[BUFSIZE];
	int n;

	if ( (n = recv(sockfd, buff, BUFSIZE, 0)) < 0)	{
	    if (errno == ECONNRESET){
		close(sockfd);
		events[i].data.fd = -1;
	    }
	    else
		printf("readline error");
	}
	else if (n == 0){
	    close(sockfd);
	    events[i].data.fd = -1;
	}
	/*buff[n] = '\0';*/
	*data = buff;
	return n;
}

void buf_swap(char *dst, char *res){
	strcpy(dst, res);
	res = NULL;
	free(res);
	res = dst;
}

int get_len(char *c){
	/*printf("%s\n", p);*/
	char *q;
	strtok(c, ":");
	q=strtok(NULL, ":") ;
	return atoi(q);
}

ssize_t Socket_send(int sockfd, char* buffer, size_t buflen){
	ssize_t tmp;
	size_t total = buflen;
	char *buffsend = buffer;
	while(total > 0 && buffsend != NULL){
		tmp = send(sockfd, buffsend, total, 0);

		if(tmp < 0)
		{
			if(errno == EINTR)
				break;
			if(errno == EAGAIN)
			{
				sleep(1);
				printf("i sleep 1 s\n");
				continue;
			}
		}	
		
		total -= tmp;
		buffsend += (size_t)tmp;
		/*printf("send tmp is %d\n", tmp);
		p += tmp;*/
	}
	return (0);
}	
